import geom.Vector;

import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.Iterator;


import processing.core.*;
public class Anchor extends Vector{
	public static int nextID = 0;
	public int id;
	boolean up;
	Edge edge;
	ArrayList edges;
	ArrayList spaces;
	int prefSpace = 0;
	FitResult result;
	public Anchor(Edge e, float x, float y, boolean up){
		super(x, y , 0);
		this.up = up;
		edge = e;
		spaces = new ArrayList();
		result = new FitResult(this);
		setID();
	}
	
	public void addEdge(Edge e){
		edges.add(e);
	}
	
	public void merge(Anchor a){
		if(a.id == id) return;
		Iterator i = edges.iterator();
		while(i.hasNext()){
			Edge e1 = (Edge)i.next();
			Iterator ii = a.edges.iterator();
			while(ii.hasNext()){
				Edge e2 = (Edge)i.next();
				if(e1.id != e2.id){
					addEdge(e2);
					e2.removeAnchor(a);
				}
			}
		}
	}
	
	public void addSpace(Space s){
		spaces.add(s);
	}
	
	public FitResult testFit(RectNode r, RectNode bounds){
		FitResult result = null;
		float totalArea = 0;
		Rectangle rect = new Rectangle(r);
		Iterator s = spaces.iterator();
		float bestScore = Float.POSITIVE_INFINITY;
		FitResult bestResult = null;
		int i = 0;
		while(s.hasNext()){
			Space space = (Space)s.next();
			totalArea += space.getArea();
			
			placeRect(rect, space);
			if(space.contains(rect)){
				int fits = space.getDimFits(rect);
				if(fits >= Rectangle.CONTAINED){
					result = new FitResult(this);
					result.prefSpace = i;
					result.fits = true;
					result.dimFits = fits;
					result.boundsIncrease = bounds.newBoundingBox(rect).getArea() / bounds.getArea();
					result.spaceEfficiency = rect.getArea() / space.getArea();
					result.space = space;
					result.rect = rect;
					float score = result.getScore();
					System.out.println("score" + score);
					if(score < bestScore){
						bestResult = result;
						bestScore = score;
					}
				}
			}
		}
		if(bestResult != null){
			prefSpace = bestResult.prefSpace;
			this.result = bestResult;
		}
		return bestResult;
	}
	
	public Space getSpace(int i){
		return (Space)spaces.get(i);
	}
	
	
	
	
	public void placeRect(Rectangle rn, Space s){
		float ax = x;
		float ay = y;
		int o = getOrientation(s)[0];
		if(o == BTM){
			ay -= rn.h;
			if(!up)
				ax -= rn.w;
		}
		if(o == RIGHT){
			ax -= rn.w;
			if(!up)
				ay -= rn.h;
		}
		rn.moveTo(ax, ay);
	}
	
	public String toString(){
		StringBuffer sb = new StringBuffer();
		sb.append(" Anchor pos:");
		sb.append(x);
		sb.append(" ");
		sb.append(y);
		sb.append(" up ");
		sb.append(up);
		sb.append(" numSpaces " + spaces.size());
		return sb.toString();
	}
	boolean selected = false;
	public void draw(PApplet pa, PFont font){
		pa.pushMatrix();
		pa.translate(x, y);
		pa.ellipse(0, 0, 6, 6);
		if(up) pa.translate(0, 25);
		else pa.translate(0, -25);
		pa.textFont(font, 10);
		pa.text("S: " + result.getScore(), 0, 0);
		pa.text("BI: " + result.boundsIncrease, 0, 11);
		pa.text("SE: " + result.spaceEfficiency, 0, 22);

		pa.popMatrix();
	}
	
	public void isSelected(float x, float y){
		if(this.x - 6 < x && this.x + 6 > x){
			if(this.y - 6 < y && this.y + 6 > y){
				selected = true;
				return;
			}
		}
		selected = false;
	}
	public void setID(){
		id = nextID;
		if(nextID > 128000)
			nextID = 0;
	}
	
	public boolean isEqual(Anchor a){
		if(a.up != up) return false;
		if(a.x != x) return false;
		if(a.y != y) return false;
		return true;
	}

	public static int TOP = 0;
	public static int BTM = 1;
	public static int LEFT = 2;
	public static int RIGHT = 3;
	public int[] getOrientation(Space s){
		int o[] = new int[2];
		o[0] = -1;
		o[1] = -1;
		if(x == s.x){
			o[0] = LEFT;
			if(y == s.y)
				o[1] = TOP;
			else if(y == s.y + s.w)
				o[1] = BTM;
		}
		else if(x == s.x + s.w){
			o[0] = RIGHT;
			if(y == s.y)
				o[1] = TOP;
			else if(y == s.y + s.w)
				o[1] = BTM;
		}
		else if(y == s.y){
			o[0] = TOP;
				
		}
		else if(y == s.y + s.h){
			o[0] = BTM;
		}

		return o;
	}
	
	public static Anchor getBestAnchor(RectNode rn, RectNode bounds,ArrayList al){
		Anchor bestAnchor = null;
		float bestScore = Float.POSITIVE_INFINITY;
		Iterator a = al.iterator();
		while(a.hasNext()){
			Anchor anchor = (Anchor)a.next();
			FitResult result = anchor.testFit(rn, bounds);
			if(result != null){
				float score = result.getScore();
				if(score < bestScore){
					bestAnchor = anchor;
					bestScore = score;
				}
			}
			
		}
		return bestAnchor;
	}
	
	public static void sortAnchors(ArrayList a){
		Collections.sort(a, new ScoreComp());
	}

	private static class ScoreComp implements Comparator{
		public ScoreComp(){
			
		}
		public int compare(Object arg0, Object arg1) {
			// TODO Auto-generated method stub
			Anchor a1 = (Anchor)arg0;
			Anchor a2 = (Anchor)arg1;
			FitResult fr1 = a1.result;
			FitResult fr2 = a2.result;
			float score1 = fr1.getScore();
			float score2 = fr2.getScore();
			float diff = score1 - score2;
			if(diff > 0) return 1;
			if(diff < 0) return -1;
			else return 0;
		}
		
	}
}